/**
 * Copyright (c) 2017-2018, zengjintao (1913188966@qq.com).
 * <p>
 * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.gnu.org/licenses/lgpl-3.0.txt
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jfast.framework.web.session;

import com.jfast.framework.kit.StrKit;
import com.jfast.framework.web.cache.JfastCache;
import java.util.Enumeration;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import javax.servlet.ServletContext;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionContext;

@SuppressWarnings("deprecation")
public class JfastHttpSession implements HttpSession {

	private static final long SESSION_TIME = TimeUnit.DAYS.toSeconds(1);
	private static final String COOKIE_CACHE_NAME = "JSESSIONID";

	private JfastCache jfastCache;

	public JfastHttpSession(JfastCache jfastCache){
		if(jfastCache == null)
			throw  new RuntimeException("jfastCache can not be null");
        this.jfastCache = jfastCache;
	}

	@Override
	public Object getAttribute(String key) {
		return jfastCache.get(COOKIE_CACHE_NAME, generateKey(key));
	}

	@Override
	public Enumeration<String> getAttributeNames() {
		return null;
	}

	@Override
	public long getCreationTime() {
		return 0;
	}

	@Override
	public String getId() {
		return getOrCreateSessionId();
	}

	private String getOrCreateSessionId(){
		String sessionid = getCookie(COOKIE_CACHE_NAME);
		if (StrKit.isNotEmpty(sessionid)) {
			return sessionid;
		}

		sessionid = RequestContext.getRequestManager().getRequestAttr(COOKIE_CACHE_NAME);
		if (StrKit.isNotEmpty(sessionid)) {
			return sessionid;
		}

		sessionid = UUID.randomUUID().toString().replace("-", "");
		RequestContext.getRequestManager().setRequestAttr(COOKIE_CACHE_NAME, sessionid);
		setCookie(COOKIE_CACHE_NAME, sessionid, (int) SESSION_TIME);
		return sessionid;
	}

	@Override
	public long getLastAccessedTime() {
		return 0;
	}

	@Override
	public int getMaxInactiveInterval() {
		return 0;
	}

	@Override
	public ServletContext getServletContext() {
		return null;
	}

	@Override
	public HttpSessionContext getSessionContext() {
		return null;
	}

	@Override
	public Object getValue(String name) {
		return jfastCache.get(COOKIE_CACHE_NAME, generateKey(name));
	}

	@SuppressWarnings("unchecked")
	@Override
	public String[] getValueNames() {
		List<Object> names = jfastCache.getKeys(COOKIE_CACHE_NAME);
		return (String[])names.toArray();
	}

	@Override
	public void invalidate() {

	}

	@Override
	public boolean isNew() {
		return false;
	}

	@Override
	public void putValue(String name, Object value) {
        jfastCache.put(COOKIE_CACHE_NAME, generateKey(name),value);
	}

	@Override
	public void removeAttribute(String key) {

	}

	@Override
	public void removeValue(String key) {

	}

	@Override
	public void setAttribute(String name, Object value) {
		putValue(name,value);
	}

	@Override
	public void setMaxInactiveInterval(int arg0) {

	}

	private String generateKey(String name){
		return String.format("%s:%s", getOrCreateSessionId(), name);
	}

	/**
	 * @param name
	 * @param value
	 * @param maxAgeInSeconds
	 */
	private void setCookie(String name, String value, int maxAgeInSeconds) {
		Cookie cookie = new Cookie(name, value);
		cookie.setMaxAge(maxAgeInSeconds);
		cookie.setPath("/");
		cookie.setHttpOnly(true);
		RequestContext.getRequestManager().getResponse().addCookie(cookie);
	}

	/**
	 * @param name
	 * @return
	 */
	private String getCookie(String name) {
		Cookie cookie = getCookieObject(name);
		return cookie != null ? cookie.getValue() : null;
	}

	/**
	 * @param name
	 * @return
	 */
	private Cookie getCookieObject(String name) {
		Cookie[] cookies = RequestContext.getRequestManager().getRequest().getCookies();
		if (cookies != null){
			for (Cookie cookie : cookies){
				if (cookie.getName().equals(name)){
					return cookie;
				}
			}
		}
		return null;
	}
}
